import pygame
import os
import random
import pygame
import math

from pygame.locals import *
from coloredsprite import ColoredSprite

class Ball(ColoredSprite):
    BASE_SPEED = 6
    MAX_SPEED = 12

    def __init__(self, x, y):
        ColoredSprite.__init__(self, ("img", "ball.png"))
    
        self.speed = Ball.BASE_SPEED
                
        self.x = x
        self.y = y
        
        #randomize initial horizontal direction
        if random.random() > 0.5:
            self.move_horizontal = 1
        else:
            self.move_horizontal = -1
            
        self.move_vertical = -1
        
        hit_sound_path = os.path.join("sfx", "pew.ogg")
        self.hit_sound = pygame.mixer.Sound(hit_sound_path)
        
        paddle_sound_path = os.path.join("sfx", "click.ogg")
        self.paddle_sound = pygame.mixer.Sound(paddle_sound_path)
        
        fail_sound_path = os.path.join("sfx", "fail.ogg")
        self.fail_sound = pygame.mixer.Sound(fail_sound_path)
        
    def get_speed_bonus(self):
        return (self.speed - Ball.BASE_SPEED) + 1
        
    #vector reflection, for bouncing
    def reflect(self, normal):
        #dot of speed and normal
        v_x = normal[0] * self.move_horizontal
        v_y = normal[1] * self.move_vertical
        
        #multiply by normal * 2
        v_x *= normal[0] * 2
        v_y *= normal[1] * 2
        
        #subtract speed
        v_x -= self.move_horizontal
        v_y -= self.move_vertical
        
        #negate
        self.move_horizontal = -v_x
        self.move_vertical = -v_y
        
    def update(self, world):
        for step in range(self.speed):
            prev_x = self.x
            prev_y = self.y
        
            self.x += self.move_horizontal
            self.y += self.move_vertical
            
            #bounce off paddle if it's in the way and the ball is moving downwards
            paddle = world.get_player()
            paddle_right = paddle.get_x() + paddle.get_width()
            bottom = self.y + (self.texture.get_height() / 2);
            if self.move_vertical > 0 and bottom > paddle.get_y() and self.x > paddle.get_x() and self.x < paddle_right:
                #the bounce angle from the paddle depends on where the ball hit
                bounce_pos = (self.x - paddle.get_x()) / float(paddle.get_width())
                bounce_pos -= 0.5 #so hits on the left are -0.5..0 and hits on the right are 0..0.5
                #multiplying by 2 here would allow the ball to bounce completely flat
                bounce_pos *= 1.75
                
                self.move_horizontal = bounce_pos
                self.move_vertical = -(1 - math.fabs(bounce_pos)) #normalized - up movement
                
                #speed decreases whenever the ball hits the paddle
                self.speed = max(Ball.BASE_SPEED, self.speed - 1)
                
                paddle.set_color(self.color)
                
                self.paddle_sound.play()
            else:
                #check if we hit a brick
                hit_result = world.get_bricks().brick_hit_test((self.x, self.y))
                
                if hit_result != False:
                    #the hit test returns a rect and a color if it was a hit
                    hit_rect = hit_result[0]
                    hit_color = hit_result[1]
                    
                    if prev_x >= hit_rect.right:
                        self.reflect((1, 0))
                    elif prev_x < hit_rect.left:
                        self.reflect((-1, 0))
                    elif prev_y >= hit_rect.bottom:
                        self.reflect((0, 1))
                    elif prev_y < hit_rect.top:
                        self.reflect((0, -1))
                        
                    #award points for hit
                    points = self.get_speed_bonus() * 100
                    world.add_score(points)
                        
                    #speed up with each brick hit
                    self.speed = min(Ball.MAX_SPEED, self.speed + 1)
                    
                    #change color to match the hit
                    self.set_color(hit_color)
                    
                    self.hit_sound.play()
                else:
                    #bounce off edges
                    if self.x < 0:
                        self.reflect((1, 0))
                    elif self.x > pygame.display.get_surface().get_width():
                        self.reflect((-1, 0))
                    
                    if self.y < 0:
                        self.reflect((0, 1))
                    elif self.y > pygame.display.get_surface().get_height():
                        #special case: hitting the bottom is bad! you missed the paddle
                        self.reflect((0, -1))
                        #speed resets
                        self.speed = Ball.BASE_SPEED
                        #lose a life
                        world.lose_life()
                        
                        self.set_color((255, 255, 255))
                        paddle.set_color((255, 255, 255))
                        
                        self.fail_sound.play()
        
    def draw(self, screen):
        draw_x = self.x - (self.texture.get_width() / 2);
        draw_y = self.y - (self.texture.get_width() / 2);
    
        screen.blit(self.get_texture(), (draw_x, draw_y))